package com.qf.jwt.security.auth;

import com.qf.common.constant.URLConstant;
import com.qf.common.domain.admin.dos.SysUser;
import com.qf.common.utils.ToolUtils;
import com.qf.common.domain.admin.mapper.SysMenuMapper;
import com.qf.jwt.util.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.function.Supplier;

/**
 * @author : sin
 * @date : 2024/6/11 12:59
 * @Description : 通过拦截器方式动态实现权限校验
 */

/**
 * 动态鉴权原理
 * 用户拥有权限比如 admin拥有 user:add  接口/user/add需要用户admin具有user:add才能访问
 * 用户根据sys_user_perm获取自己的权限，perm表中btn_perm(user:add) 获取请求的接口 去匹配menu的path获取对应的menu_id并根据menu_id来获取对应的btn_perm
 * 然后两个进行字符串对比
 */
@Slf4j
@Component
public class MyauthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
    @Override
    public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        AuthorizationManager.super.verify(authentication, object);
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        if (!(authentication.get().getPrincipal() instanceof SysUser)) {
            throw new AccessDeniedException("匿名不可访问!");
        }
        //获取Spring Boot应用的上下文路径
        String contextPath = requestAuthorizationContext.getRequest().getContextPath();
        //访问的接口地址
        String requestURI = requestAuthorizationContext.getRequest().getRequestURI();
        //匿名地址直接访问
        // 注意：这里使用startsWith进行检查，以确保只移除实际匹配的上下文路径
        if (requestURI.startsWith(contextPath)) {
            requestURI = requestURI.substring(contextPath.length());
        }
        if (ToolUtils.contains(requestURI, URLConstant.LOGIN_URLS)) {
            return new AuthorizationDecision(true);
        }
        requestURI = requestURI.replaceFirst("^/admin", "");

        // 当前登录人的权限
        SysUser user = (SysUser) authentication.get().getPrincipal();
        // 异常和边界条件处理：检查用户权限是否为空
        if (user.getPerms() == null || user.getPerms().isEmpty()) {
            return new AuthorizationDecision(false); // 直接返回未授权，避免不必要的数据库访问
        }
        //查询当前请求的接口需要哪些权限能访问
        List<String> allMenuPerms = loadPermsFromDatabase(requestURI, 2);
        // 检查用户是否有任何权限匹配
        String[] array = user.getPerms().toArray(new String[0]);
        for (String auth : allMenuPerms) {
            if(ToolUtils.contains(auth,array)){
                return new AuthorizationDecision(true);
            }
        }
        throw new AccessDeniedException(user.getUsername() + ",没有访问:" + requestURI + "的权限");
    }
    //
    private List<String> loadPermsFromDatabase(String path, Integer type) {
        try {
            // 根据path和菜单类型从数据库获取菜单信息
            List<String> perms = BeanUtils.getBean(SysMenuMapper.class).selectPermByPathAndType(path,type);
            return perms;
        } catch (Exception e) {
            // 异常处理逻辑
            throw new RuntimeException("获取数据异常", e);
        }
    }
}